/**
 * 指定物理内存区域的接口。
 * 
 * 物理内存可能不是连续的，此时就需要用多个内存区域来表达整个可用的内存空间。
 */
#ifndef _AHAMOLETT_PHYSICAL_AREA_H_
#define _AHAMOLETT_PHYSICAL_AREA_H_

#include <mm/mm_types.h>

/* 最大可设定的内存区域数量。 */
#define MAX_PHYSICAL_AREAS  32

/**
 * @brief 添加一个内存区域。
 * 
 * 系统事先会保留一块固定的空间用于存放内存区域的信息，该函数会往其中添加一个内存区域。所有的
 * 内存区域最后会被转换成 zone_struct 结构体，并交由伙伴系统管理。
 * 
 * 记录的内存区域的数量不能超过 MAX_PHYSICAL_AREAS。
 * 
 * 为了满足后面的计算，后添加的内存区域必须起始地址高于先添加的内存区域。
 * 
 * @param physical_start 内存区域的物理起始地址。
 * @param area_length 内存区域的长度。
 * 
 * @return 添加成功返回0，失败返回-1。
 */
extern int add_physical_area(
    unsigned long physical_start, 
    unsigned long area_length
);

/**
 * @brief 读取一个内存区域的信息。
 * 
 * 通过该函数可以读取通过 add_physical_area 函数添加的内存区域信息。
 * 
 * @param area_num 记录的内存区域的编号。
 * @param[out] physical_start 返回内存区域的物理起始地址。
 * @param[out] area_length 返回内存区域的长度。
 * 
 * @retval true area_num 有效。
 * @retval false area_num 无效。
 */
extern int get_physical_area(
    unsigned long area_num, 
    unsigned long *physical_start, 
    unsigned long *area_length
);

/**
 * @brief 返回当前已经被添加的内存区域数量。
 * 
 * @return unsigned long 已经被添加的内存区域数量。
 */
extern unsigned long get_physical_areas_count(void);

/**
 * @brief 遍历所有已经被添加的内存区域信息。
 * 
 * 对 for 循环的封装，用于在内存管理系统初始化过程中获取所有被添加的内存区域信息。
 * 
 * @param pos 作为游标遍历所有被添加的内存区域。
 * @param physical_start 当前内存区域的物理起始地址。
 * @param area_length 当前内存区域的长度。
 */
#define for_each_physical_area(pos, physical_start, area_length)    \
    for (   (pos) = 0;  \
            get_physical_area(pos, &(physical_start), &(area_length));  \
            (pos)++)

#endif
